﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace WMemoryProfiler
{
    class GCHandleComparer : IEqualityComparer<GCHandle>
    {

        #region IEqualityComparer<GCHandle> Members

        public bool Equals(GCHandle x, GCHandle y)
        {
            return Object.ReferenceEquals(x.Target, y.Target);
        }

        public int GetHashCode(GCHandle obj)
        {
            object target = obj.Target;
            if (target == null)
                return 0;

            return RuntimeHelpers.GetHashCode(target);
        }

        #endregion
    }

    /// <summary>
    /// Store an object array as weak references to be able to track which objects have been removed and which ones
    /// have been added.
    /// </summary>
    class ObjectMarker : IDisposable
    {
        HashSet<GCHandle> TaggedObjects = new HashSet<GCHandle>(new GCHandleComparer());
        public ObjectMarker(IEnumerable<object> objects)
        {
            foreach(var obj in objects)
            {
                TaggedObjects.Add(GCHandle.Alloc(obj, GCHandleType.WeakTrackResurrection));
            };
        }

        public object[] GetNewObjects(IEnumerable<object> objects)
        {
            List<object> newObj = new List<object>();
            foreach (var obj in objects)
            {
                GCHandle handle = default(GCHandle);
                try
                {
                    handle = GCHandle.Alloc(obj, GCHandleType.WeakTrackResurrection);
                    if (!TaggedObjects.Contains(handle))
                    {
                        newObj.Add(obj);
                    }
                }
                finally
                {
                    if (handle.IsAllocated)
                    {
                        handle.Free();
                    }
                }
            }

            return newObj.ToArray();
        }


        #region IDisposable Members
        public void Dispose()
        {
            foreach (var handle in TaggedObjects)
            {
                handle.Free();
            }
            TaggedObjects = null;
        }

        #endregion
    }
}
